/*
 * Copyright (c) 2023-2023 elsfs Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.elsfs.cloud.common.security.config;

import java.util.LinkedHashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

/**
 * 聚合自定义的过滤器配置
 *
 * @author zeng
 */
@Slf4j
public final class CustomSecurityConfigurer
    extends AbstractSecurityConfigurer<CustomSecurityConfigurer> {

  private final Map<
          Class<? extends AbstractSecurityFilterConfigurer<?, ?>>,
          AbstractSecurityFilterConfigurer<?, ?>>
      configurers = createConfigurers();

  /** 是否全部替换成功处理器 */
  private boolean customSuccessHandler = false;

  /** 是否全部替换失败处理器 */
  private boolean customFailureHandler = false;

  @Override
  public CustomSecurityConfigurer successHandler(
      AuthenticationSuccessHandler authenticationSuccessHandler) {
    this.customSuccessHandler = true;
    return super.successHandler(authenticationSuccessHandler);
  }

  @Override
  public CustomSecurityConfigurer failureHandler(AuthenticationFailureHandler failureHandler) {
    customFailureHandler = true;
    return super.failureHandler(failureHandler);
  }

  /**
   * 手机号密码登录配置
   *
   * @param phonePasswordCustomizer 自定义配置
   * @return this
   */
  public CustomSecurityConfigurer phonePassword(
      Customizer<PhonePasswordAuthenticationSecurityConfigurer> phonePasswordCustomizer) {
    phonePasswordCustomizer.customize(
        getConfigurer(PhonePasswordAuthenticationSecurityConfigurer.class));
    return this;
  }

  /**
   * 手机号短信登录配置
   *
   * @param phoneSmsCustomizer 自定义配置
   * @return this
   */
  public CustomSecurityConfigurer phoneSms(
      Customizer<PhoneSmsAuthenticationSecurityConfigurer> phoneSmsCustomizer) {
    phoneSmsCustomizer.customize(getConfigurer(PhoneSmsAuthenticationSecurityConfigurer.class));
    return this;
  }

  /**
   * 自定义用户名密码登录配置
   *
   * @param usernamePasswordCustomizer 配置信息
   * @return this
   */
  public CustomSecurityConfigurer usernamePassword(
      Customizer<UsernamePasswordAuthenticationConfigurer> usernamePasswordCustomizer) {
    usernamePasswordCustomizer.customize(
        getConfigurer(UsernamePasswordAuthenticationConfigurer.class));
    return this;
  }

  @Override
  public void init(HttpSecurity http) throws Exception {
    for (AbstractSecurityFilterConfigurer<?, ?> configurer : this.configurers.values()) {
      configurer.init(http);
    }
  }

  @Override
  public void configure(HttpSecurity http) throws Exception {
    ClientRegistrationRepository clientRegistrationRepository =
        http.getSharedObject(ClientRegistrationRepository.class);
    for (AbstractSecurityFilterConfigurer<?, ?> configurer : this.configurers.values()) {
      if (configurer instanceof AppletLoginAuthenticationConfigurer) {
        if (clientRegistrationRepository == null) {
          LOGGER.warn("未成功配置 小程序登录");
          continue;
        }
      }

      configurer.configure(http);
      if (customSuccessHandler) {
        configurer.filter.setAuthenticationSuccessHandler(successHandler);
      }
      if (customFailureHandler) {
        configurer.filter.setAuthenticationFailureHandler(failureHandler);
      }
    }
  }

  private Map<
          Class<? extends AbstractSecurityFilterConfigurer<?, ?>>,
          AbstractSecurityFilterConfigurer<?, ?>>
      createConfigurers() {
    Map<
            Class<? extends AbstractSecurityFilterConfigurer<?, ?>>,
            AbstractSecurityFilterConfigurer<?, ?>>
        configurers = new LinkedHashMap<>();
    configurers.put(
        PhonePasswordAuthenticationSecurityConfigurer.class,
        new PhonePasswordAuthenticationSecurityConfigurer());
    configurers.put(
        PhoneSmsAuthenticationSecurityConfigurer.class,
        new PhoneSmsAuthenticationSecurityConfigurer());
    configurers.put(
        UsernamePasswordAuthenticationConfigurer.class,
        new UsernamePasswordAuthenticationConfigurer());
    configurers.put(
        AppletLoginAuthenticationConfigurer.class, new AppletLoginAuthenticationConfigurer());
    return configurers;
  }

  /**
   * 默认配置
   *
   * @param http http
   * @throws Exception e
   */
  public static void applyDefaultSecurity(HttpSecurity http) throws Exception {
    CustomSecurityConfigurer configurer =
        new CustomSecurityConfigurer()
            .usernamePassword(Customizer.withDefaults())
            .phonePassword(Customizer.withDefaults())
            .phoneSms(Customizer.withDefaults());
    http.with(configurer, Customizer.withDefaults());
  }

  @SuppressWarnings("unchecked")
  private <T> T getConfigurer(Class<T> type) {
    return (T) this.configurers.get(type);
  }
}
